package com.linkgie.galaxyframework.kvstorage.spi;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;
import java.util.Set;

import com.linkgie.galaxyframework.kvstorage.DataCodec;
import com.linkgie.galaxyframework.kvstorage.KVStorageSettings;

/**
 * 键值存储引擎的 SPI ；
 * 
 * @author spring
 *
 */
public interface KVStorageProvider {

	/**
	 * 存储设置；
	 * 
	 * @return
	 */
	KVStorageSettings getSettings();

	/**
	 * 默认支持的数据类型；
	 * <p>
	 * 
	 * 实现者应返回除了基本类型、基本类型的包装类型、String类型之外的支持作为值的类型；<br>
	 * 
	 * 基本类型、基本类型的包装类型、String类型是受存储管理器的默认支持的；
	 * 
	 * @return
	 */
	Set<Class<?>> getSupportedDataTypes();

	/**
	 * 返回指定类型的数据编码器
	 * <p>
	 * 
	 * 编码器用于对指定的类型的数据值进行处理；
	 * <p>
	 * 
	 * 存储引擎管理器在加载存储引擎 SPI 时，将根据支持的数据类型（{@link #getSupportedDataTypes()}）
	 * 作为参数依次调用一次此方法，并缓存方法返回的数据编解码器实例；
	 * <p>
	 * 
	 * 实现者应遵循以下规则：<br>
	 * 1. 对于（{@link #getSupportedDataTypes()}）返回的类型，必须返回一个对应的 {@link DataCodec}
	 * 实例，否则存储引擎管理器将引发异常；<br>
	 * 
	 * 2. 此方法只会被存储引擎管理器在加载此 SPI 实现时调用一次，然后一直持有返回的数据编码器实例，实现者应确保数据编码器能够一直持续工作；
	 * 
	 * @param <T>
	 * @param dataType
	 * @return
	 */
	<T> DataCodec<T> getDataCodec(Class<T> dataType);

	/**
	 * 基本类型数据编码器
	 * <p>
	 * 
	 * 此编码器用于对基本类型、基本类型的包装类型、String类型的数据值进行处理。
	 * <p>
	 * 
	 * 实现者应遵循以下规则：<br>
	 * 
	 * 1. 实现者可以选择性地实现此方法，如果返回 null，则键值存储管理器会提供默认实现；<br>
	 * 
	 * @return
	 */
	PrimitiveDataCodec getPrimitiveDataCodec();

	/**
	 * 存储数据库 URI 采用的 Scheme ，用于表示本实现对应的数据库类型；
	 * 
	 * @return
	 */
	String getURIScheme();

	/**
	 * 根据 URI 生成对应的数据仓库 id ；
	 * <p>
	 * 实现者应确保：<br>
	 * 1. 相同 uri 参数值返回相同的数据仓库 id；<br>
	 * 2. 不同 uri 参数值返回不同的数据仓库 id；<br>
	 * <p>
	 * 
	 * @param uri
	 * @return
	 */
	default String getRepositoryId(String uri) {
		try {
			return getRepositoryId(new URI(uri));
		} catch (URISyntaxException e) {
			throw new IllegalURISyntaxException("Illegal syntax of kvrepository uri[" + uri + "]! --" + e.getMessage(),
					e);
		}
	}

	/**
	 * 根据 URI 生成对应的数据仓库 id ；
	 * <p>
	 * 实现者应确保：<br>
	 * 1. 相同 uri 参数值返回相同的数据仓库 id；<br>
	 * 2. 不同 uri 参数值返回不同的数据仓库 id；<br>
	 * <p>
	 * 
	 * @param uri
	 * @return
	 */
	String getRepositoryId(URI uri);

	/**
	 * 解析字符串形式的数据仓库地址的语法，返回有效的 URI 对象；
	 * <p>
	 * 
	 * 如果 uri 参数的语法不正确，将引发 {@link IllegalURISyntaxException} 异常；
	 * <p>
	 * 
	 * @param uri 字符串形式的数据仓库地址
	 * @return 有效的 URI 对象;
	 * @throws IllegalURISyntaxException uri 参数的语法不正确
	 */
	URI resolveRepositoryURI(String uri) throws IllegalURISyntaxException;

	/**
	 * 返回或者创建指定 URI 表示的键值数据仓库；
	 * 
	 * @param uri    数据仓库的 URI；
	 * @param dbHome 数据仓库的本地主目录；
	 * @return
	 */
	default KVDatabase createDatabase(String uri, KVDatabaseHome dbHome) {
		return createDatabase(uri, null, dbHome);
	}

	/**
	 * 返回或者创建指定 URI 表示的键值数据仓库；
	 * 
	 * @param uri    数据仓库的 URI；
	 * @param config 配置属性；可选参数，为 null 时采取默认配置；
	 * @param dbHome 数据仓库的本地主目录；
	 * @return
	 */
	default KVDatabase createDatabase(String uri, Properties config, KVDatabaseHome dbHome) {
		try {
			return createDatabase(new URI(uri), config, dbHome);
		} catch (URISyntaxException e) {
			throw new IllegalURISyntaxException("Illegal syntax of kvrepository uri[" + uri + "]! --" + e.getMessage(),
					e);
		}
	}

	/**
	 * 返回或者创建指定 URI 表示的键值数据仓库；
	 * 
	 * @param uri    数据仓库的 URI；
	 * @param dbHome 数据仓库的本地主目录；
	 * @return
	 */
	default KVDatabase createDatabase(URI uri, KVDatabaseHome dbHome) {
		return createDatabase(uri, null, dbHome);
	}

	/**
	 * 返回或者创建指定 URI 表示的键值数据仓库；
	 * 
	 * @param uri    数据仓库的 URI；
	 * @param config 配置属性；可选参数，为 null 时采取默认配置；
	 * @param dbHome 数据仓库的本地主目录；
	 * @return
	 */
	KVDatabase createDatabase(URI uri, Properties config, KVDatabaseHome dbHome);
}
